#include "BaseShip.h"
#include "BtOgrePG.h"
#include "BtOgreGP.h"
#include "BtOgreExtras.h"
#include "OgreConsole.h"
#include "BaseCannon.h"
#include "BaseLauncher.h"
#include <OgreSubEntity.h>
#include "PhysicsManager.h"
#include "GameState.hpp"

using namespace Ogre;

BaseShip::BaseShip(Ogre::String name, Ogre::SceneManager* sceneMgr, Ogre::Vector3 sPos)
{
	m_MoveSpeed = 50;
	m_MaxSpeed = 200;
	
	m_RotateSpeed = 20;
	m_MaxRotateSpeed = 1;
	OgreConsole::getSingleton().print("Ship created");
	m_pSceneMgr = sceneMgr;

	m_ShipEntity =  m_pSceneMgr->createEntity(name, "normal_hull.mesh");
	m_ShipEntity ->setMaterialName("Flat");
	m_ShipNode = m_pSceneMgr->getRootSceneNode()->createChildSceneNode(name + "node");

	m_ShipNode->attachObject(m_ShipEntity);
	m_ShipNode->setPosition(sPos);
	
	//Create shape.
	BtOgre::StaticMeshToShapeConverter converter(m_ShipEntity);
    m_ShipShape = converter.createBox();

	m_TranslateVector = Vector3::ZERO;
	m_RotateVector = Vector3::ZERO;

    //Calculate inertia.
    btScalar mass = 50000;
    btVector3 inertia = btVector3(1,1,1);
    m_ShipShape->calculateLocalInertia(mass, inertia);

    //Create BtOgre MotionState (connects Ogre and Bullet).
    shipState = new BtOgre::RigidBodyState(m_ShipNode);

    //Create the Body.
    m_ShipBody = new btRigidBody(mass, shipState, m_ShipShape, inertia);
	//m_ShipBody->setCollisionFlags(m_ShipBody->getCollisionFlags() | COL_SHIP);
	m_ShipEntity->setQueryFlags(PLAYER_CHARACTER);

	for(int i = 0; i < 6; ++i){
		BaseCannon* cannon = new BaseCannon(name + "CannonRight" + Ogre::StringConverter::toString(i),  m_pSceneMgr, m_ShipNode, Vector3(2, 0, -6 + (1.5 * i)), 0);
		m_Cannons.push_back(cannon);
	}
	for(int i = 0; i < 6; ++i){
		BaseCannon* cannon = new BaseCannon(name + "CannonLeft" + Ogre::StringConverter::toString(i),  m_pSceneMgr, m_ShipNode, Vector3(-2, 0, -6 + (1.5 * i)), 1);
		m_Cannons.push_back(cannon);
	}

	for(int i = 0; i < 2; ++i){
		BaseLauncher* launcher = new BaseLauncher(name + "LauncherLeft" + Ogre::StringConverter::toString(i),  m_pSceneMgr, m_ShipNode, Vector3(-1, 0.25 - (0.5 * i), -10.5), Quaternion(sqrt(0.5), 0, 0, 0));
		m_Launchers.push_back(launcher);
	}

	for(int i = 0; i < 2; ++i){
		BaseLauncher* launcher = new BaseLauncher(name + "LauncherRight" + Ogre::StringConverter::toString(i),  m_pSceneMgr, m_ShipNode, Vector3(1, 0.25 - (0.5 * i), -10.5), Quaternion(sqrt(0.5), 0, 0, 0));
		m_Launchers.push_back(launcher);
	}

	m_NumCannons = 12;
	m_NumLaunchers = 4;

	m_CameraBaseNode = m_ShipNode->createChildSceneNode (name + "_base_camera", Vector3 (0, 0, 0));
	m_SightNode = m_CameraBaseNode->createChildSceneNode (name + "_sight", Vector3 (0, 0, -10));
    m_CameraNode = m_CameraBaseNode->createChildSceneNode (name + "_camera", Vector3 (0, 40, 20));

	PhysicsManager::getSingletonPtr()->addPhysicsShip(m_ShipBody);
}


BaseShip::~BaseShip(void)
{
}

void BaseShip::updateShip(double timeSinceLastFrame)
{
	m_MoveScale = m_MoveSpeed  * timeSinceLastFrame;
    m_RotScale  = m_RotateSpeed * timeSinceLastFrame;
	
	m_ShipBody->clearForces();
	//btQuaternion temp = m_ShipBody->getOrientation();
	
	Ogre::Vector3 UserForce = m_TranslateVector;
	btVector3 relativeForce = (btVector3(UserForce.x, 0 ,UserForce.z));

	//Gets translation vector relative to direction
	btMatrix3x3& boxRot = m_ShipBody->getWorldTransform().getBasis();
	btVector3 correctedForce = boxRot * relativeForce;

	m_ShipBody->setActivationState(DISABLE_DEACTIVATION);
	m_ShipBody->applyForce(correctedForce,btVector3(0,0,0));

	Ogre::Vector3 RotateForce = m_RotateVector;
	m_ShipBody->applyForce(btVector3(RotateForce.x, 0 , 0),btVector3(0,0,10));
	m_ShipBody->applyForce(btVector3(-RotateForce.x, 0 , 0),btVector3(0,0,-10));

	shipState->setWorldTransform(m_ShipBody->getWorldTransform());

	//Resets vectors
	m_TranslateVector = Vector3::ZERO;
	m_RotateVector = Vector3::ZERO;

	//Update Cannons
	for(int i = 0; i < m_NumCannons; ++i)
	{
		m_Cannons[i]->updateCannon(timeSinceLastFrame);
	}

	//Update Launcher
	for(int i = 0; i < m_NumLaunchers; ++i)
	{
		m_Launchers[i]->updateLauncher(timeSinceLastFrame);
	}

	//m_CameraBaseNode->yaw(Degree(0.1f));

	tickCallBack();
}

void BaseShip::updateTarget(Ogre::Vector3 target)
{

	//m_SightNode->setPosition(Vector3(target.x, 0, target.z));
	//m_PlayerShip->updateTarget(target);
	for(int i = 0; i < m_NumCannons; ++i)
	{
		m_Cannons[i]->updateTarget(target);
	}
	for(int i = 0; i < m_NumLaunchers; ++i)
	{
		m_Launchers[i]->updateTarget(target);
	}
}

void BaseShip::updateCamera(Degree yaw, Degree pitch)
{
	Quaternion cameraRot = m_CameraBaseNode->getOrientation();
	Ogre::Matrix3 mat;
	cameraRot.ToRotationMatrix(mat);
	Radian yRad;
	Radian pRad;
	Radian rRad;
	mat.ToEulerAnglesYXZ(yRad, pRad, rRad);
	Degree yDeg = yRad + yaw;
	Degree xDeg = pRad + pitch;
	Degree zDeg = rRad;

	if (xDeg.valueDegrees() >= 45) {
		xDeg = 45;
	}
	else if (xDeg.valueDegrees() <= 10) {
		xDeg = 10;
	}

	mat.FromEulerAnglesYXZ((Ogre::Degree)yDeg, xDeg, zDeg);
	cameraRot.FromRotationMatrix(mat);

	//find a target
	m_CameraBaseNode->setOrientation(cameraRot);

	//m_CameraBaseNode->yaw(yaw);
	//m_CameraBaseNode->pitch(pitch);
}

void BaseShip::firePrimaryWeapon()
{
	for(int i = 0; i < m_NumCannons; ++i)
	{
		m_Cannons[i]->fireCannon();
	}
}

void BaseShip::fireSecondaryWeapon()
{
	for(int i = 0; i < m_NumLaunchers; ++i)
	{
		m_Launchers[i]->fireLauncher();
	}
}

void BaseShip::rotateLeft()
{
	m_RotateVector.x = m_RotScale;
}
void BaseShip::rotateRight()
{
	 m_RotateVector.x = -m_RotScale;
}
void BaseShip::moveLeft()
{
	m_TranslateVector.x = -m_MoveScale;
}
void BaseShip::moveRight()
{
	 m_TranslateVector.x = m_MoveScale;
}
void BaseShip::moveDown()
{
	m_TranslateVector.z = m_MoveScale;
}
void BaseShip::moveUp()
{
	m_TranslateVector.z = -m_MoveScale;
}

void BaseShip::tickCallBack()
{
	 // mShipBody is the spaceship's btRigidBody
    btVector3 velocity = m_ShipBody->getLinearVelocity();
    btScalar speed = velocity.length();
    if(speed > m_MaxSpeed) {
        velocity *= m_MaxSpeed/speed;
        m_ShipBody->setLinearVelocity(velocity);
    }

	btVector3 angleVelocity = m_ShipBody->getAngularVelocity();
    btScalar angleSpeed = angleVelocity.length();
    if(angleSpeed > m_MaxRotateSpeed) {
        angleVelocity *= m_MaxRotateSpeed/angleSpeed;
        m_ShipBody->setAngularVelocity(angleVelocity);
    }
}

Ogre::SceneNode* BaseShip::getCameraNode() {
      return m_CameraNode;
 }

Ogre::SceneNode* BaseShip::getSightNode() {
      return m_SightNode;
 }

void BaseShip::changeDebugVisibility()
{
	for(int i = 0; i < m_NumCannons; ++i)
	{
		m_Cannons[i]->changeDebugVisibility();
	}
	for(int i = 0; i < m_NumLaunchers; ++i)
	{
		m_Launchers[i]->changeDebugVisibility();
	}
}